home *** CD-ROM | disk | FTP | other *** search
Text File | 1990-06-24 | 38.1 KB | 822 lines | [TEXT/CCL ] |
- ; (c) Copyright 1990 by University of Massachusetts. All rights reserved.
- ; This software was conceived, designed, and written by Dan Suthers
- ; while supported by the National Science Foundation under grant number
- ; MDR 8751362, and by a fellowship from Apple Computer, Inc., Cupertino,
- ; CA. Partial support was also received from the Office of Naval Research
- ; under a University Research Initiative Grant, contract N00014-86-K-0764.
- ; Mr. Suthers created this software under his own initiative while in an
- ; academic relationship with the University of Massachusetts. The above
- ; copyright notice was a condition placed by University lawyers on approval
- ; of distribution of this software by Apple Computer, and is not meant to
- ; imply that this software was created in an employment or "work for hire"
- ; relationship between the University and Mr. Suthers.
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ; File: DACTN-Browser.lisp
- ; Author: Dan Suthers
- ; Created: 09-Aug-88 00:20:26
- ; Modified: 22-Jun-90 02:38:38 (Dan Suthers)
- ; Language: Common Lisp
- ; Package: DACTN
- ;
- ; Description: Graphical browsing and editing of DACTNs.
- ;
- ; (c) Copyright 1988, by Daniel D. Suthers
- ; Department of Computer and Information Science
- ; University of Massachusetts
- ; Amherst, Massachusetts 01003
- ;
- ; This software was conceived, designed, and written by Dan Suthers
- ; while supported by the National Science Foundation under grant number
- ; MDR 8751362, and by a fellowship from Apple Computer, Inc., Cupertino,
- ; CA. Partial support was also received from the Office of Naval Research
- ; under a University Research Initiative Grant, contract N00014-86-K-0764.
- ; I wish to acknowledge the generous support of Beverly Woolf, who obtained
- ; the above grants and encouraged me to pursue my own research interests in
- ; her lab. This work would not have been possible without the resources and
- ; stimulating environment of the Computer and Information Science department.
- ;
- ; Permission to use, modify, and distribute this software is granted subject
- ; to the following restrictions and understandings:
- ; 1. The file header, including this notice, shall be retained, and may be
- ; extended to include documentation of modifications to the software.
- ; 2. This material is for nonprofit educational and research purposes only.
- ; Users are requested, but not required, to inform Mr. Suthers of any
- ; noteworthy uses of this software.
- ; 3. Mr. Suthers and the University of Massachusetts make no warrantee or
- ; representation that the operation of this software will be error free,
- ; and are under no obligation to provide any services.
- ; 4. Any user of such software agrees to indemnify and hold harmless Mr.
- ; Suthers and the University of Massachusetts from all claims arising
- ; out of the use or misuse of this software, or arising out of any
- ; accident, injury, or damage whatsoever, and from all costs, counsel
- ; fees, and liabilities incurred in or about any such claim, action, or
- ; proceeding brought thereon.
- ; 5. All materials and reports developed as a consequence of the use of
- ; this software shall duly acknowledge such use, in accordance with
- ; the usual standards of acknowledging credit in academic research.
- ;
- ; Status: Usable. Recommend rewriting for specialized interfaces.
- ;
- ; Tested: Macintosh II Coral/Allegro 03-Nov-88 00:31:11
- ;
- ; Changes:
- ; 04-Sep-88 ARG-GEN editable; can no longer delete referenced node;
- ; can mouse recursive dactn to graph it; misc. cleanup.
- ; 23-Sep-88 Reuses same window when regraphing (window destruction and
- ; creation was annoying; now it preserves the size of the window too);
- ; Dactns saved pretty printed; Trace added; Interpret and Trace options
- ; on menu. Thanks to Lauren Blau for suggestions.
- ; 25-Sep-88 Updating for new grapher mouse method implementation. Now
- ; all actions are available on the first menu.
- ; 28-Sep-88 Keeps track of modified DACTNs; menu access to this list.
- ; When adding Action or Test, you can specify New and get a Fred window.
- ; 26-Oct-88 Choice of labeling graphed dactn nodes with name or associated
- ; action; box types changed updated consistent with other grapher code;
- ; One less menu selection required by get-arc-from-user.
- ; 01-Nov-88 Updated for SM changes.
- ; 14-Nov-88 Graphs "orphan" nodes at top of screen; doesn't put up menu
- ; for Delete Arc when there is only one arc.
- ; 09-Dec-88 Minor change to graphed DACTN window title.
- ; 27-Dec-88 Eliminating graph-node-parents.
- ; 17-Oct-89 Interpret-dactn now called by eval-enqueue when invoked from
- ; window or menu. Dave Shaffer had a problem with other windows getting
- ; locked up, until I did this.
- ; 07-Nov-89 Wrote menu-item-update for label-type-item and trace-item.
- ; 30-Jan-90 Updated for version 1.3.1.
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-
- (in-package :DACTN)
-
- (export '(
- dactn->graph-view
- dactn-modified
- dactn-unmodified
- graph-dactn
- modified-dactns
- ))
-
- (require :misc)
- (require :sm)
- (require :smedit)
- (require :dactns)
- (require :dialogue)
- (require :grapher)
-
- ;;; To get past ccl compiler bug: it seems to hit wind:symbols before
- ;;; executing the require that creates the package, and gives a "no
- ;;; package WIND" error.
- (use-package :wind)
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;; Used to fill the OBJECT slot of a GRAPH-NODE.
-
- (defstruct (OBJECT-SPEC
- (:type list)
- (:constructor make-object-spec (type owner itself)))
- (TYPE :dactn :type (member :dactn :dactn-node :dactn-arc :exit))
- (OWNER nil :type symbol) ; a dactn name
- (ITSELF nil :type t))
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;; Keeping track of modified DACTNS for saving to file ...
-
- (let ((*modified-dactns* nil))
- (defun DACTN-MODIFIED (dactn)
- "dactn-modified <dactn>
- records the dactn as modified."
- (setf *modified-dactns* (adjoin dactn *modified-dactns*)))
- (defun DACTN-UNMODIFIED (dactn)
- "dactn-unmodified <dactn>
- removes the dactn from the list of modified dactns."
- (setf *modified-dactns* (delete dactn *modified-dactns*)))
- (defun MODIFIED-DACTNS ()
- "modified-dactns
- returns a list of dactns recorded as being modified."
- *modified-dactns*)
- )
-
- ;;; We redefine this to mark a dactn as modified if the user uses sm:edits.
-
- (setf (sm:type-info 'dactn :after-edit)
- '(lambda (d)
- (dactn-modified d)
- (initialize-dactn d)))
-
- ;;; If nil, node name used; if T, action name used in graphs.
-
- (defvar *LABEL-USING-ACTION-NAMES* nil)
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-
- (defun GRAPH-DACTN (dactn &key (node-font '("monaco" 9)))
- "graph-dactn <dactn> [Function]
- Puts up a grapher window and graphs the DACTN in it."
- (check-type dactn symbol)
- (assert (sm:gets 'dactn dactn) (dactn) "[GRAPH-DACTN] ~S is not a dactn name.")
- (ccl:oneof grapher:*graph-window*
- :graph-view (dactn->graph-view dactn :node-font node-font)
- :window-title
- (let ((*print-case* :capitalize))
- (format nil "DACTN ~A" dactn))))
-
- (defun DACTN-MOUSE-METHOD (gw gv gn)
- ;; Bypassing usual menu approach since we want menus to be sensitive to node type.
- (declare (symbol gv gn))
- (let ((object-spec
- (grapher:graph-node-object (sm:gets 'grapher:graph-node gn))))
- (case (object-spec-type object-spec)
- ((:dactn) (dactn-mouse-method-for-dactn gw gv gn object-spec))
- ((:dactn-node) (dactn-mouse-method-for-dactn-node gw gv gn object-spec))
- ((:dactn-arc) (dactn-mouse-method-for-dactn-arc gw gv gn object-spec))
- ((:exit) (dactn-mouse-method-for-exit gw gv gn object-spec)))))
-
- (defun CONS-IN-MIDDLE-OF-LIST (object list)
- (if (null list)
- (list object)
- (cons (first list)
- (cons-in-middle-of-list-r object (rest list) 2))))
-
- (defun CONS-IN-MIDDLE-OF-LIST-R (object remaining-list in-so-far)
- (if (<= (length remaining-list) in-so-far)
- (cons object remaining-list)
- (cons (first remaining-list)
- (cons-in-middle-of-list-r object (rest remaining-list) (1+ in-so-far)))))
-
- (defun DACTN->GRAPH-VIEW (dactn &key (node-font '("monaco" 9)))
- (check-type dactn symbol)
- (assert (sm:gets 'dactn dactn) (dactn) "[DACTN->GRAPH-VIEW] Unknown DACTN ~S" dactn)
- (let* ((dactn-struct (sm:gets 'dactn dactn))
- (dactn-node-defs (dactn-nodes dactn-struct))
- (dactn-nodes->graph-nodes nil)
- (dactn-arc-graph-nodes nil)
- (non-orphans nil))
- (declare (list dactn-node-defs dactn-nodes->graph-nodes dactn-arc-graph-nodes
- recursive-dactns->graph-nodes non-orphans))
-
- ;; Define all the graph nodes for dactn nodes.
- (dolist (name+struct dactn-node-defs)
- (declare (cons name+struct))
- (let ((node-name (gensym "GraphedDactnNode-")))
- (push
- (cons (car name+struct)
- (grapher:create-graph-node
- node-name
- (if *label-using-action-names*
- (symbol-name (second (dactn-node-action (cdr name+struct))))
- (symbol-name (car name+struct))) ; LABEL
- nil ; CHILDREN
- (if (eq (first (dactn-node-action (cdr name+struct)))
- :dactn)
- :round-rect
- :rect) ; BOX-STYLE
- t ; CONNECTOR
- (make-object-spec :dactn-node dactn name+struct))) ; OBJECT
- dactn-nodes->graph-nodes)))
-
- ;; For each arc, define a graph node and insert appropriate graph node pointers.
- (dolist (name+struct dactn-node-defs)
- (declare (cons name+struct))
-
- ;; Reverse operation to get the arcs drawn in the right order easily.
- (do* ((arc-ptr (reverse (dactn-node-arcs (cdr name+struct))) (cdr arc-ptr))
- (arc nil)
- (arc-count (length (dactn-node-arcs (cdr name+struct))) (1- arc-count))
- (number-arcs (> arc-count 1)))
- ((null arc-ptr))
- (declare (list arc-ptr arc) (fixnum arc-count))
- (setf arc (first arc-ptr))
- ;; This is needed to identify "orphan" nodes to be graphed.
- (if (third arc) ; Null third arc -> EXIT which has no dactn node.
- (pushnew (cdr (assoc (third arc) dactn-nodes->graph-nodes))
- non-orphans))
- (let ((arc-name (gensym "GraphedDactnArc-")))
- (push
- (grapher:create-graph-node
- arc-name
- (if number-arcs ; LABEL
- (format nil "~A: ~A"
- arc-count
- (string-capitalize (symbol-name (first arc))))
- (format nil "~A" (string-capitalize (symbol-name (first arc)))))
- nil ; CHILDREN
- :none ; BOX-STYLE
- nil ; CONNECTOR
- (make-object-spec :dactn-arc dactn (cons (car name+struct) arc))) ; OBJECT
- dactn-arc-graph-nodes)
-
- ;; Create children if needed and link.
- (case (second arc)
- ;; Node children have been created: link to nodes at both ends of the arc.
- ((:goto)
- (setf (grapher:graph-node-children
- (sm:gets 'grapher:graph-node arc-name))
- (list (cdr (assoc (third arc) dactn-nodes->graph-nodes))))
- (push arc-name
- (grapher:graph-node-children
- (sm:gets 'grapher:graph-node
- (cdr (assoc (car name+struct) dactn-nodes->graph-nodes))))))
-
- ;; Exit: arc has no argument. Make bogus graph node child, link.
- ((:exit)
- (push arc-name
- (grapher:graph-node-children
- (sm:gets 'grapher:graph-node
- (cdr (assoc (car name+struct) dactn-nodes->graph-nodes)))))
- (setf (grapher:graph-node-children
- (sm:gets 'grapher:graph-node arc-name))
- (list (grapher:create-graph-node
- (gensym "GRAPHED-EXIT-")
- "EXIT" ; LABEL
- nil ; CHILDREN
- :rect ; BOX-STYLE
- t ; CONNECTOR
- (make-object-spec :exit dactn nil))))))))) ; OBJECT
-
- ;; Make the graph view, with a node corresponding to the DACTN being the root.
- (grapher:create-graph-view
- (utils:unique-symbol (format nil "~A " dactn))
- (cons-in-middle-of-list ; ROOTS
- (grapher:create-graph-node
- (gensym "GRAPHED-DACTN-")
- (symbol-name dactn) ; Label
- (if (dactn-start-node dactn-struct) ; Children
- (list (cdr (assoc (dactn-start-node dactn-struct)
- dactn-nodes->graph-nodes))))
- :oval ; Box-Style
- t ; Connector
- (make-object-spec :dactn dactn nil)) ; Object
- ;; Including "orphan" dactn nodes as roots.
- (mapcan #'(lambda (dn+gn)
- (declare (cons dn+gn))
- (unless (or (member (cdr dn+gn) non-orphans)
- (eq (car dn+gn) (dactn-start-node dactn-struct)))
- (list (cdr dn+gn))))
- dactn-nodes->graph-nodes))
- 99 ; DEPTH-BOUND
- :vertical-tree ; STYLE
- :as-found ; ORDERING
- node-font
- '("chicago" 12) ; TEXT-FONT
- 10 ; BORDER-WIDTH
- nil ; INFO
- #'dactn-mouse-method))) ; MOUSE-METHOD
-
- (eval-when (compile eval)
- (defmacro REMAKE-DACTN-VIEW (gw gv object-spec)
- (declare (ignore gv))
- `(ccl:ask ,gw
- (let ((new-gv (dactn->graph-view (object-spec-owner ,object-spec))))
- (grapher:set-graph-view new-gv)
- (ccl:set-window-title
- (sm:prints 'grapher:graph-view new-gv :style :name :stream nil))
- (ccl:window-select)
- (ccl:view-draw-contents)
- (unless (grapher:windows-using-graph-view gv)
- (grapher:dispose-graph-view gv)))))
- )
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;; Editing DACTN as a whole
-
- (defun DACTN-MOUSE-METHOD-FOR-DACTN (gw gv gn object-spec)
- (declare (symbol gv gn) (list object-spec))
- (let* ((dactn (object-spec-owner object-spec))
- (dactn-struct (sm:gets 'dactn dactn))
- (edit-action
- (wind:menu-dialogue
- '(|Create New Node| |Change Start Node| |Delete Node| |Interpret DACTN|
- |Update Graph for Changes| |Change Comments| |Change Type|
- |Edit LISP Definition| |Inspect this DACTN| |Inspect Graph Node|)
- "What do you want to do with DACTN ~S?" dactn)))
- (declare (symbol dactn edit-action))
- (ecase edit-action
- ((|Create New Node|)
- (push (get-new-node-from-user dactn) (dactn-nodes dactn-struct))
- (dactn-modified dactn)
- (remake-dactn-view gw gv object-spec))
- ((|Change Start Node|)
- (setf (dactn-start-node dactn-struct)
- (wind:menu-dialogue (dactn-node-names dactn)
- "What is the new start node for ~S?" dactn))
- (dactn-modified dactn)
- (remake-dactn-view gw gv object-spec))
- ((|Delete Node|)
- (let ((node (wind:menu-dialogue (dactn-node-names dactn)
- "Delete what node from ~S?" dactn)))
- (cond
- ((eq node (dactn-start-node dactn-struct))
- (ccl:ed-beep)
- (wind:message-dialogue
- "Node ~A is currently the start node, and cannot be deleted."
- node))
- ((member node (nodes-referenced-by-arcs dactn-struct))
- (ccl:ed-beep)
- (wind:message-dialogue
- "Node ~A is referenced by an arc out of another node, and cannot be deleted."
- node))
- (T
- (setf (dactn-nodes dactn-struct)
- (delete node (dactn-nodes dactn-struct)
- :key #'car))
- (dactn-modified dactn)
- (remake-dactn-view gw gv object-spec)))))
- ((|Interpret DACTN|)
- (ccl:eval-enqueue `(interpret-dactn ',(object-spec-owner object-spec))))
- ((|Update Graph for Changes|)
- (remake-dactn-view gw gv object-spec))
- ((|Change Comments|) ; must improve: no good for multi-lined comments.
- (setf (dactn-comments dactn-struct)
- (wind:get-string-default-dialogue
- (dactn-comments dactn-struct)
- "Please provide your new comments for DACTN ~S" dactn))
- (dactn-modified dactn))
- ((|Change Type|)
- (setf (dactn-type dactn-struct)
- (read-from-string
- (wind:get-string-dialogue
- "What is the new type classification for ~S?" dactn)))
- (dactn-modified dactn))
- ((|Edit LISP Definition|) ; :after-edit method for dactn will mark as modified
- (sm:edits 'dactn dactn)
- (wind:message-dialogue
- "You are responsible for redrawing the DACTN graph when done."))
- ((|Inspect this DACTN|) (inspect dactn-struct))
- ((|Inspect Graph Node|) (inspect (sm:gets 'grapher:graph-node gn))))))
-
- (defun GET-NEW-NODE-FROM-USER (dactn)
- ;; Returns minimally operational node.
- (let ((node-name (read-from-string
- (wind:get-string-dialogue
- "Give a symbolic name for a new node in ~S:" dactn))))
- (if (member node-name (dactn-node-names dactn))
- (progn (ccl:ed-beep) (wind:message-dialogue "That node already exists."))
- (cons node-name
- (make-dactn-node
- :action (get-action-from-user node-name dactn))))))
-
- (defun GET-ACTION-FROM-USER (node-name dactn)
- (let ((type (wind:menu-dialogue
- '("Regular DACTN-Action" "Invoke another DACTN")
- "What kind of action is ~S in ~S to have?" node-name dactn)))
- (if (string= type "Regular DACTN-Action")
- (list :action (get-action-name-from-user
- "What DACTN-Action will be invoked at node ~S?" node-name))
- (list :dactn (get-dactn-name-from-user
- "What DACTN will be invoked at node ~S?" node-name)))))
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;; Editing DACTN nodes
-
- (defun DACTN-MOUSE-METHOD-FOR-DACTN-NODE (gw gv gn object-spec)
- (declare (symbol gv gn) (list object-spec))
- (let* ((dactn (object-spec-owner object-spec))
- (node (car (object-spec-itself object-spec)))
- (struct (cdr (object-spec-itself object-spec)))
- (edit-action
- (wind:menu-dialogue
- (if (eq (first (second (third object-spec))) :dactn)
- '(|Graph Nested DACTN|
- |Add Arc| |Change Arc Ordering| |Delete Arc|
- |Change Associated Action| |Edit Associated Action|
- |Edit ARG-GEN| |Inspect this DACTN Node| |Inspect Graph Node|)
- '(|Add Arc| |Change Arc Ordering| |Delete Arc|
- |Change Associated Action| |Edit Associated Action|
- |Edit ARG-GEN| |Inspect this DACTN Node| |Inspect Graph Node|))
- "What do you want to do with node ~S in DACTN ~S?" node dactn)))
- (declare (symbol dactn node edit-action))
- (case edit-action
- ((|Graph Nested DACTN|)
- (graph-dactn (second (second (object-spec-itself object-spec)))))
- ((|Add Arc|)
- (setf (dactn-node-arcs struct)
- (nconc (dactn-node-arcs struct) (list (get-arc-from-user dactn node))))
- (dactn-modified dactn)
- (remake-dactn-view gw gv object-spec))
- ((|Change Arc Ordering|)
- (setf (dactn-node-arcs struct)
- (get-arc-order-from-user node (dactn-node-arcs struct)))
- (dactn-modified dactn)
- (remake-dactn-view gw gv object-spec))
- ((|Delete Arc|)
- (setf (dactn-node-arcs struct)
- (remove-arc-specified-by-user node (dactn-node-arcs struct)))
- (dactn-modified dactn)
- (remake-dactn-view gw gv object-spec))
- ((|Change Associated Action|)
- ;; Whether regraphing depends on whether changed between dactn-action and dactn
- (let ((prev-action (first (dactn-node-action struct))))
- (setf (dactn-node-action struct) (get-action-from-user node dactn))
- (unless (eq prev-action (first (dactn-node-action struct)))
- (remake-dactn-view gw gv object-spec))
- (dactn-modified dactn)))
- ((|Edit Associated Action|)
- ;; This does not constitute modification of the DACTN in itself
- (if (eq (first (dactn-node-action struct)) :action)
- (sm:edits 'dactn-action (second (dactn-node-action struct)))
- (sm:edits 'dactn (second (dactn-node-action struct)))))
- ((|Edit ARG-GEN|)
- ;; This needs to be abstracted out!
- (let* ((title (format nil "<ARG-GEN for ~A in ~A>" node dactn))
- (*print-pretty* t)
- (setf-string
- (format nil
- ";;; Evaluate buffer when done editing~
- ~%(setf (dactn::dactn-node-arg-gen~
- ~% (cdr (assoc '~S~
- ~% (dactn::dactn-nodes (sm:gets 'dactn:dactn '~S)))))~
- ~%~
- ~% '~A~
- ~%~
- ~% )~
- ~%(dactn:dactn-modified '~S)
- ~%(ccl:ask (ccl:front-window) (ccl:window-close))"
- node dactn (prin1-to-string (dactn-node-arg-gen struct)) dactn))
- (the-editor nil) (width 0) (height 0))
- (multiple-value-bind
- (columns rows)
- (wind:message-size setf-string)
- (declare (integer columns rows) (optimize speed))
- (setf columns (max columns (+ 10 (length title))))
- (setf width (min 580 (max 250 (* 7 columns))))
- (setf height
- (min 300
- (max 100
- (cond ((< rows 4) (* (+ 4 sm::*editor-window-font-height*)
- rows))
- ((< rows 12) (* (+ 2 sm::*editor-window-font-height*)
- rows))
- (t (* sm::*editor-window-font-height* rows)))))))
- (setf the-editor
- (ccl:oneof ccl:*fred-window*
- :window-title title
- :window-position (sm:next-window-position width height)
- :window-size (ccl:make-point width height)
- :window-show t
- :window-font sm::*editor-window-font*
- :window-type :document-with-zoom
- :close-box-p t
- :scratch-p t
- :package *package*))
- (ccl:buffer-insert (ccl:ask the-editor (ccl:window-buffer)) setf-string)
- (ccl:ask the-editor (ccl:window-update))))
- ((|Inspect this DACTN Node|) (inspect struct))
- ((|Inspect Graph Node|) (inspect (sm:gets 'grapher:graph-node gn))))))
-
- (defun DACTN-MOUSE-METHOD-FOR-EXIT (gw gv gn object-spec)
- (declare (symbol gn) (list object-spec) (ignore gv gw))
- (let* ((dactn (object-spec-owner object-spec))
- (edit-action
- (wind:menu-dialogue
- '(|Inspect this Exit Object| |Inspect Graph Node|)
- "What do you want to do with this Exit in ~S?" dactn)))
- (declare (symbol dactn edit-action))
- (case edit-action
- ((|Inspect this Exit Object|) (inspect object-spec))
- ((|Inspect Graph Node|) (inspect (sm:gets 'grapher:graph-node gn))))))
-
- (defun GET-ARC-FROM-USER (dactn node)
- (let* ((test (get-test-name-from-user
- "What DACTN-Test do you want on the new arc for ~A?" node))
- (target
- (wind:menu-dialogue (cons :exit (dactn-node-names dactn))
- "If ~A succeeds, Go To which node?"
- test)))
- (if (eq target :exit)
- (list test :exit)
- (list test :goto target))))
-
- (defun GET-ARC-ORDER-FROM-USER (node arcs)
- (do ((new-arcs (list :head))
- (chosen-arc nil)
- (count 1 (1+ count)))
- ;; Don't force them to choose the last arc from a menu, but watch for null arcs.
- ((null (cdr arcs))
- (if arcs (append (cdr new-arcs) arcs) (cdr new-arcs)))
- (setf chosen-arc
- (wind:menu-dialogue arcs
- "Which arc is #~A in the arc ordering for ~A?"
- count node))
- (setf arcs (delete chosen-arc arcs :test #'equal))
- (nconc new-arcs (list chosen-arc))))
-
- (defun REMOVE-ARC-SPECIFIED-BY-USER (node arcs)
- (if (null (rest arcs))
- nil
- (remove (wind:menu-dialogue arcs "Delete which arc from the arcs for ~A?" node)
- arcs :test #'equal)))
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;; Editing DACTN ARCS
-
- (defun DACTN-MOUSE-METHOD-FOR-DACTN-ARC (gw gv gn object-spec)
- (declare (symbol gv gn) (list object-spec))
- (let* ((dactn (object-spec-owner object-spec))
- (node (car (object-spec-itself object-spec)))
- (arc (cdr (object-spec-itself object-spec)))
- (edit-action
- (wind:menu-dialogue
- (ccase (second arc)
- ((:goto)
- '(|Change Target Node|
- |Change Test| |Change Arc Type| |Edit Test| |Inspect Graph Node|))
- ((:exit)
- '(|Change Test| |Change Arc Type| |Edit Test| |Inspect Graph Node|)))
- "What do you want to do with arc ~%~S~%belonging to node ~S in DACTN ~S?"
- arc node dactn)))
- (case edit-action
- ((|Change Target Node|)
- (setf (third arc)
- (wind:menu-dialogue (dactn-node-names dactn)
- "Choose node to Go To from ~S:" node))
- (dactn-modified dactn)
- (remake-dactn-view gw gv object-spec))
- ((|Change Test|)
- (setf (first arc)
- (get-test-name-from-user "Choose new DACTN-TEST for~%~S:" arc))
- (dactn-modified dactn)
- (remake-dactn-view gw gv object-spec))
- ((|Change Arc Type|)
- (setf (second arc) (wind:menu-dialogue *arc-types*
- "Choose new arc-type for~%~S:" arc))
- (dactn-modified dactn)
- (case (second arc)
- ((:exit) (setf (cddr arc) nil))
- ((:goto)
- (if (null (cddr arc))
- (setf (cddr arc)
- (list (wind:menu-dialogue (dactn-node-names dactn)
- "Choose node to Go To from ~S:" node))))))
- (remake-dactn-view gw gv object-spec))
- ((|Edit Test|) (sm:edits 'dactn-test (first arc)))
- ((|Inspect Graph Node|) (inspect (sm:gets 'grapher:graph-node gn))))))
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;; Helpers
-
- (defun GET-DACTN-NAME-FROM-USER (message &rest args)
- (let ((dactn
- (wind:menu-dialogue
- (cons "Make a New DACTN" (sm:instances 'dactn))
- (apply #'format nil message args))))
- (when (equal "Make a New DACTN" dactn)
- (setf dactn (sm:new-instance-name 'dactn))
- (funcall (sm:creator 'dactn) dactn)
- (graph-dactn dactn))
- dactn))
-
- (defun GET-TEST-NAME-FROM-USER (message &rest args)
- (let ((test
- (wind:menu-dialogue
- (cons "Make a New Test" (sm:instances 'dactn-test))
- (apply #'format nil message args))))
- (when (equal "Make a New Test" test)
- (setf test (sm:new-instance-name 'dactn-test))
- (funcall (sm:creator 'dactn-test) test)
- (sm:edits 'dactn-test test))
- test))
-
- (defun GET-ACTION-NAME-FROM-USER (message &rest args)
- (let ((action
- (wind:menu-dialogue
- (cons "Make a New Action" (sm:instances 'dactn-action))
- (apply #'format nil message args))))
- (when (equal "Make a New Action" action)
- (setf action (sm:new-instance-name 'dactn-action))
- (funcall (sm:creator 'dactn-action) action)
- (sm:edits 'dactn-action action))
- action))
-
- (defun DACTN-NODE-NAMES (dactn)
- (mapcar #'car (dactn-nodes (sm:gets 'dactn dactn))))
-
- (defun NODES-REFERENCED-BY-ARCS (dactn-struct)
- (let ((nodes-referenced nil))
- (dolist (node-name+struct (dactn-nodes dactn-struct))
- (dolist (test+arc (dactn-node-arcs (cdr node-name+struct)))
- (if (eq (first (cdr test+arc)) :goto)
- (push (second (cdr test+arc)) nodes-referenced))))
- nodes-referenced))
-
- (defun SAVE-DACTN (dactn path)
- "save-dactn <dactn> [Function]
- Writes the macro definitions of <dactn> to a file specified by <path>."
- (check-type dactn symbol)
- (assert (sm:gets 'dactn dactn) (dactn)
- "[GRAPHER:SAVE-DACTN] Unknown dactn ~S" dactn)
- (check-type path (or simple-string pathname))
- (let ((*print-pretty* nil) (*print-escape* t)
- (*print-circle* nil) (*print-case* :upcase) (*print-array* t)
- #+:ccl (ccl:*print-structure* t))
- (with-open-file (stream path
- :direction :output
- :if-exists :supersede)
- (format stream ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;; Graph View ~S~%;;; Saved by SAVE-DACTN ~A~%;;; On ~A, a ~A~%"
- dactn
- (multiple-value-bind
- (second minute hour date month year)
- (get-decoded-time)
- (declare (integer second minute hour date month year))
- (format nil "~2,'0D-~A-~2,'0D ~2,'0D:~2,'0D:~2,'0D"
- date
- (case month
- ((1) "Jan") ((2) "Feb") ((3) "Mar") ((4) "Apr")
- ((5) "May") ((6) "Jun") ((7) "Jul") ((8) "Aug")
- ((9) "Sep") ((10) "Oct") ((11) "Nov") ((12) "Dec"))
- (- year 1900)
- hour minute second))
- (machine-instance)
- (machine-type))
- (format stream "~%(in-package ~S)~%~%" (package-name *package*))
- (sm:prints 'dactn dactn :style :pretty-macro :stream stream)
- (format stream "~&~%;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;; EOF"))
- path))
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-
- (defparameter *DACTN-MENU*
- (let* ((line-item
- (ccl:oneof ccl:*menu-item*
- :menu-item-title "-"))
- (graph-item
- (ccl:oneof ccl:*menu-item*
- :menu-item-title "Graph/Edit DACTN ..."
- :menu-item-action
- #'(lambda ()
- (let ((dactn
- (wind:menu-dialogue
- (sm:instances 'dactn)
- "Which DACTN do you wish to graph and edit?")))
- (graph-dactn dactn)))))
- (label-type-item
- (ccl:oneof ccl:*menu-item*
- :menu-item-title "Label Using Action Names"
- :menu-item-action
- '(progn (setf *label-using-action-names*
- (not *label-using-action-names*))
- (if *label-using-action-names*
- (ccl:set-menu-item-check-mark t)
- (ccl:set-menu-item-check-mark nil)))))
- (new-dactn-item
- (ccl:oneof ccl:*menu-item*
- :menu-item-title "New DACTN ..."
- :menu-item-action
- #'(lambda ()
- (let ((dactn-name (sm:new-instance-name 'dactn)))
- (create-dactn dactn-name)
- (dactn-modified dactn-name)
- (graph-dactn dactn-name)))))
- (modified-dactns-item
- (ccl:oneof ccl:*menu-item*
- :menu-item-title "Modified DACTNs ..."
- :menu-item-action
- #'(lambda ()
- (dolist (dactn (wind:multiple-menu-dialogue
- (modified-dactns)
- "These DACTNs are currently marked as modified. Select any you wish to unmodify."))
- (dactn-unmodified dactn)))))
- (save-item
- (ccl:oneof ccl:*menu-item*
- :menu-item-title "Save DACTN ..."
- :menu-item-action
- #'(lambda ()
- (let* ((d (wind:menu-dialogue
- (sm:instances 'dactn)
- "Which DACTN do you want to save?"))
- (file-path
- (pathname
- (ccl:choose-new-file-dialog
- :prompt
- (format nil "Save ~A to ..." d))))
- (backup-path
- (make-pathname
- :host (pathname-host file-path)
- :device (pathname-device file-path)
- :directory (pathname-directory file-path)
- :name (pathname-name file-path)
- :type "bak")))
- (if (probe-file file-path)
- (progn
- (if (probe-file backup-path)
- (delete-file backup-path))
- (rename-file file-path backup-path)
- (format T "~&;~A backed up to ~A"
- (namestring file-path)
- (namestring backup-path))))
- (setf *default-instance-file-path*
- (directory-namestring file-path))
- (ccl:eval-enqueue
- `(progn
- (save-dactn ',d ',file-path)
- (dactn-unmodified ',d)
- (format T "~&;DACTN ~A saved to ~S"
- ',d
- ',(namestring file-path))))))))
- (interpret-item
- (ccl:oneof ccl:*menu-item*
- :menu-item-title "Interpret DACTN"
- :menu-item-action
- #'(lambda ()
- (ccl:eval-enqueue
- '(interpret-dactn
- (wind:menu-dialogue
- (sm:instances 'dactn)
- "Which DACTN do you want to Interpret?"))))))
- (trace-item
- (ccl:oneof ccl:*menu-item*
- :menu-item-title "Trace DACTNs"
- :menu-item-action
- '(progn (setf *trace-dactns*
- (not *trace-dactns*))
- (if *trace-dactns*
- (ccl:set-menu-item-check-mark t)
- (ccl:set-menu-item-check-mark nil)))))
- (dispose-item
- (ccl:oneof ccl:*menu-item*
- :menu-item-title "Hide This Menu"
- :menu-item-action
- '(ccl:ask *dactn-menu* (ccl:menu-deinstall))))
- (dactn-menu (ccl:oneof ccl:*menu*
- :menu-title "DACTN"
- :menu-items (list interpret-item
- trace-item
- line-item
- graph-item
- label-type-item
- line-item
- new-dactn-item
- modified-dactns-item
- save-item
- line-item
- dispose-item))))
- (ccl:defobfun (ccl:menu-item-update label-type-item) ()
- (if *label-using-action-names*
- (ccl:set-menu-item-check-mark t)
- (ccl:set-menu-item-check-mark nil)))
- (ccl:defobfun (ccl:menu-item-update trace-item) ()
- (if *trace-dactns*
- (ccl:set-menu-item-check-mark t)
- (ccl:set-menu-item-check-mark nil)))
- (ccl:ask dactn-menu (ccl:menu-install))
- (ccl:ask line-item (ccl:menu-item-disable))
- ;; Menu-dispose dumped from version 1.3.1?
- (if (and (boundp '*dactn-menu*)
- (typep *dactn-menu* ccl:*menu*))
- (ccl:ask *dactn-menu* (ccl:menu-deinstall)))
- dactn-menu))
-
- (ccl:ask ccl:*tools-menu*
- (ccl:add-menu-items
- (ccl:oneof ccl:*menu-item*
- :menu-item-title "Restore DACTN Menu"
- :menu-item-action
- #'(lambda ()
- (ccl:ask *dactn-menu*
- (unless (ccl:menu-installed-p) (ccl:menu-install)))))))
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- (provide :dactn-browser)
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;; EOF
-